#include <GL/glut.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>

float r = 0;
float u = 0;
float l = 0;
float t = 0;
GLuint texName;
GLubyte tex[64][64][4];

void init(void);
void loop(void);
void display(void);
void reshape(int width, int height);
void keyboardDown(unsigned char key, int x, int y);
void keyboardUp(unsigned char key, int x, int y);
void keyboard(unsigned char key, int state, int x, int y);
void mouse(int button, int state, int x, int y);
void displayText(void);

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(1024, 576);
    glutCreateWindow("WYX glTemplate");
    init();
    glutIdleFunc(loop);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboardDown);
    glutKeyboardUpFunc(keyboardUp);
    //glutFullScreen();
    glutMainLoop();
    return 0;
}

void lightOn(void)
{
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    //glEnable(GL_LIGHT1);
}

void lightOff(void)
{
    glDisable(GL_LIGHTING);
    glDisable(GL_LIGHT0);
    //glDisable(GL_LIGHT1);
}

void init(void)
{
    glShadeModel(GL_SMOOTH);
    glClearColor(0, 0, 0, 0);
    glClearDepth(1);

    // Blend mode
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    // Depth test
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);

    // Cull face
    glFrontFace(GL_CW);
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);

    // Polygon mode
    glPolygonMode(GL_FRONT, GL_FILL);
    //glPolygonMode(GL_BACK, GL_LINE);

    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
    glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);

    // Texture
    glGenTextures(1, &texName);
    for(int i=0; i<64; i++)
    {
        for(int j=0; j<64; j++)
        {
            tex[i][j][0] = 4*sqrt(i*i + j*j);//(510 - 4*i - 4*j)/2;
            tex[i][j][1] = 4*sqrt((64-i)*(64-i)+(j)*(j));//4*j;
            tex[i][j][2] = 0;
            tex[i][j][3] = 197;
        }
    }
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);

    // Light
    float mat_specular[] = {0.5, 0.5, 0.5, 1};
    float mat_shininess[] = {50};
    float light_position[] = {-0.5, 0.5, 1, 0};
    float light1_position[] = {1, 1, 1, 0};
    float light_direction[] = {-1, -1, -1, 0};
    float white_light[] = {1, 1, 1, 1};
    float lmodel_ambient[] = {0.1, 0.1, 0.1, 1};
    // 镜面反射光
    glMaterialfv(GL_FRONT, GL_SPECULAR, white_light);
    glMaterialfv(GL_BACK, GL_SPECULAR, white_light);
    // 反射强度
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glMaterialfv(GL_BACK, GL_SHININESS, mat_shininess);
    // 发光物
    //glMaterialfv(GL_FRONT, GL_EMISSION, mat_specular);
    glEnable(GL_COLOR_MATERIAL);

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT, white_light);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);

    /* 聚光灯
    glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
    glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light_direction);
    glLightfv(GL_LIGHT1, GL_AMBIENT, white_light);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, white_light);
    glLightfv(GL_LIGHT1, GL_SPECULAR, white_light);
    glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 10);
    glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2); */
}

void reshape(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, double(width)/double(height), 0, 1000.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void keyboardDown(unsigned char key, int x, int y)
{
    keyboard(key, 1, x, y);
}

void keyboardUp(unsigned char key, int x, int y)
{
    keyboard(key, 0, x, y);
}

void keyboard(unsigned char key, int state, int x, int y)
{
    switch(key)
    {
        case 0x1B:
            exit(0);
        case 'w':
            u -= 1;
            break;
        case 's':
            u += 1;
            break;
        case 'a':
            l -= 1;
            break;
        case 'd':
            l += 1;
            break;
        case 'u':
            t += 0.1;
            break;
        case 'j':
            t -= 0.1;
            break;
        case 'l':
            if(state) lightOn();
            else lightOff();
            break;
        default:
            break;
    }
}

void mouse(int button, int state, int x, int y)
{
    switch(button)
    {
        case GLUT_LEFT_BUTTON:
            break;
        case GLUT_MIDDLE_BUTTON:
            break;
        case GLUT_RIGHT_BUTTON:
            break;
        default:
            break;
    }
}

void loop(void)
{
    r += 1;
    display();
}

void drawCube(void)
{
        glBegin(GL_QUADS);
            glColor4f(1, 0, 0, 1);
            glNormal3f(0, 0, 1);
            glVertex3f(-1, -1, 1);
            glVertex3f(-1, 1, 1);
            glVertex3f(1, 1, 1);
            glVertex3f(1, -1, 1);
            
            glColor4f(1, 1, 0, 1);
            glNormal3f(1, 0, 0);
            glVertex3f(1, -1, -1);
            glVertex3f(1, -1, 1);
            glVertex3f(1, 1, 1);
            glVertex3f(1, 1, -1);
            
            glColor4f(0, 0, 1, 1);
            glNormal3f(0, -1, 0);
            glVertex3f(-1, -1, -1);
            glVertex3f(-1, -1, 1);
            glVertex3f(1, -1, 1);
            glVertex3f(1, -1, -1);
            
            glColor4f(1, 0, 0, 1);
            glNormal3f(0, 0, -1);
            glVertex3f(-1, 1, -1);
            glVertex3f(-1, -1, -1);
            glVertex3f(1, -1, -1);
            glVertex3f(1, 1, -1);
            
            glColor4f(1, 1, 0, 1);
            glNormal3f(-1, 0, 0);
            glVertex3f(-1, -1, 1);
            glVertex3f(-1, -1, -1);
            glVertex3f(-1, 1, -1);
            glVertex3f(-1, 1, 1);
            
            glColor4f(0, 0, 1, 1);
            glNormal3f(0, 1, 0);
            glVertex3f(-1, 1, 1);
            glVertex3f(-1, 1, -1);
            glVertex3f(1, 1, -1);
            glVertex3f(1, 1, 1);
        glEnd();
}

void displayText()
{
    char s[] = "Copyright Rockie X.Lee PRESS[L] to light";
    glColor4f(0.5, 1, 0, 1);
    glRasterPos3f(-2, 0, -1.1);
    for(int i=0; i<sizeof(s); i++)
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, s[i]);
    glRasterPos3f(-2, 0, -1);
    for(int i=0; i<sizeof(s); i++)
        glutBitmapCharacter(GLUT_BITMAP_8_BY_13, s[i]);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(0, -3, 0, 0, 0, 0, 0, 0, 1);

    displayText();
    glPushMatrix();
        glTranslatef(0, t, 0);
        glRotatef(u, 1, 0, 0);
        glRotatef(l, 0, 0, 1);
        glRotatef(r, 0, 0, 1);
        //drawCube();
    glDrawPixels(64, 64, GL_RGBA, GL_UNSIGNED_BYTE, tex);
    glReadPixels(25, 20, 64, 64, GL_RGBA, GL_UNSIGNED_BYTE, tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);

        glRotatef(90, 1, 0, 0);
        glColor4f(0, 0, 0, 0.5);
        glEnable(GL_TEXTURE_2D);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glBindTexture(GL_TEXTURE_2D, texName);
        glutSolidTeapot(0.6);
        glDisable(GL_TEXTURE_2D);
    glPopMatrix();
    glFlush();
    glutSwapBuffers();
}
